#include <stdio.h>
#include <signal.h>
#include <sys/prctl.h>
#include <unistd.h>

#include <libusb-1.0/libusb.h>

#include "launcherd.h"

extern int daemonEntryPoint( libusb_device_handle* deviceHandle, int launcherdSocket );

static void printDevice( libusb_device_handle* deviceHandle ){
	
	int res;
	
	unsigned char manufacturer[32];
	unsigned char product[32];
	
	libusb_device* dev;
	struct libusb_device_descriptor desc;
	
	//get device and device descriptor
	dev = libusb_get_device( deviceHandle );
	libusb_get_device_descriptor( dev, &desc );
	
	//get manufacturer name
	res = libusb_get_string_descriptor_ascii( deviceHandle, desc.iManufacturer, manufacturer, sizeof(manufacturer) );
	if( res < 1 ) manufacturer[0] = 0x00;
	
	//get product name
	res = libusb_get_string_descriptor_ascii( deviceHandle, desc.iProduct, product, sizeof(product) );
	if( res < 1 ) product[0] = 0x00;
	
	//print device info
	printf( "[usb] Found %04x:%04x %s %s\n", desc.idVendor, desc.idProduct, manufacturer, product );
}

/*************************************************
func usbDeviceOpen
	search and open device. Also claim interface 0.
return
	device handle on success
	NULL on error
**************************************************/
static libusb_device_handle* usbDeviceOpen( uint16_t vendor_id, uint16_t product_id ){
	
	int i;
	int err;
	libusb_device** deviceList;
	libusb_device* found = NULL;
	libusb_device_handle* deviceHandle = NULL;
	struct libusb_device_descriptor deviceDescriptor;
	ssize_t count;
	
	//get usb device list
	count = libusb_get_device_list( NULL, &deviceList );
	if( count < 0 ){
		printf( "[usb] get device list error: %li\n", count );
		return NULL;
	}
	
	//search our usb device in list
	for( i = 0; i < count; i++ ){
		//Note since libusb-1.0.16, LIBUSB_API_VERSION >= 0x01000102, this function always succeeds.
		libusb_get_device_descriptor( deviceList[i], &deviceDescriptor );
		
		if( deviceDescriptor.idVendor == vendor_id && deviceDescriptor.idProduct == product_id ){
			found = deviceList[i];
			break;
		}
	}
	
	//if device not found go to exit 
	if( !found ) goto l_listFree;
	
	//try to open device
	err = libusb_open( found, &deviceHandle );
	if( err ){
		printf( "[usb] open device error:%i\n", err );
		deviceHandle = NULL;
		goto l_listFree;
	}
	
	//try to claim interface 0
	err = libusb_claim_interface( deviceHandle, 0 );
	if( err ){
		printf( "[usb] Interface 0 claim error: %i\n", err );
		libusb_close( deviceHandle );
		deviceHandle = NULL;
	}
	
l_listFree:
	//we don't need it anymore
	libusb_free_device_list( deviceList, 1 );
	
	return deviceHandle;
}


/***************************************
func usbDeviceClose
	release interface 0 and close device
***************************************/
static void usbDeviceClose( libusb_device_handle* deviceHandle ){
	libusb_release_interface( deviceHandle, 0 );
	libusb_close( deviceHandle );
}

static int searchDevice( int launcherdSocket ){
	
	int err;
	libusb_device_handle* deviceHandle = NULL;
	
	uint16_t vendor_id  = 0x0483;
	uint16_t product_id = 0x2016;
	
	//try to init libusb
	err = libusb_init( NULL );
	if( err ){
		printf( "[usb] libusb init error: %i\n", err );
		return err;
	}
	
	//search and open device
	deviceHandle = usbDeviceOpen( vendor_id, product_id );
	
	//if device found, try to start driver
	if( deviceHandle ){
		printDevice( deviceHandle );
		err = daemonEntryPoint( deviceHandle, launcherdSocket );
		usbDeviceClose( deviceHandle );
	} else printf( "[usb] Device not found.\n" );
	
	//libusb deinit
	libusb_exit( NULL );
	return err;
}

int main( int argc, char* argv[] ){
	
	int err = 0;
	int launcherdSocket;
	
	//set thread name
	prctl( PR_SET_NAME, "main", 0, 0, 0 );
	
	//start launcherd
	launcherdSocket = launcherdStart();
	if( launcherdSocket < 0 ){
		printf( "[main] Launcherd start failed: %i\n", launcherdSocket );
		return 1;
	}
	
	//make sure the SIGPIPE doesn't disturb us
	signal( SIGPIPE, SIG_IGN );
	
	//search device and start daemon if device exist
	err = searchDevice( launcherdSocket );
	
	//Close launcherd socket to signal him go to exit
	close( launcherdSocket );
	
	printf( "[main] Exiting with code %i\n", err );
	return err;
}
